﻿using System;
using System.Diagnostics.Contracts;
using System.Windows.Input;
using Infrastructure.Events;
using Microsoft.Practices.Composite.Events;

namespace Infrastructure.ViewModels
{
    /// <summary>
    /// Data model for repositories managing a single class
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class DataModelSingle<T> : DataModel
    {
        /// <summary>
        /// The current item
        /// </summary>
        T _item;
        /// <summary>
        /// Command for saving current CatalogItem entity
        /// </summary>
        RelayCommand _saveCommand;
        /// <summary>
        /// Command for deleting current CatalogItem entity
        /// </summary>
        RelayCommand _deleteCommand;

        /// <summary>
        /// Initializes a new instance of the <see cref="DataModelSingle&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="item">The item.</param>
        public DataModelSingle(T item) : base()
        {
            Initialize(item);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DataModelSingle&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="eventAggregator">The event aggregator.</param>
        /// <param name="item">The item.</param>
        public DataModelSingle(IEventAggregator eventAggregator, T item) : base(eventAggregator)
        {
            Initialize(item);
        }

        /// <summary>
        /// Initializes the specified item.
        /// </summary>
        /// <param name="item">The item.</param>
        void Initialize(T item)
        {
            _item = item;
        }

        /// <summary>
        /// Gets a value indicating whether thye entity is a new item.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if the entity is a new item; otherwise, <c>false</c>.
        /// </value>
        protected virtual bool IsNewItem
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Gets the item.
        /// </summary>
        /// <value>The item.</value>
        public T Item
        {
            get
            {
                return _item;
            }
        }

        /// <summary>
        /// Gets the delete command.
        /// </summary>
        /// <value>The delete command.</value>
        public virtual ICommand DeleteCommand
        {
            get
            {
                Contract.Ensures(Contract.Result<ICommand>() != null);

                if (_deleteCommand == null)
                {
                    _deleteCommand = new RelayCommand(
                        param => Delete(),
                        param => CanDelete);
                }
                return _deleteCommand;
            }
        }

        /// <summary>
        /// Deletes this instance.
        /// </summary>
        protected virtual void Delete()
        {
            CatalogItemViewModel deletedItem = this as CatalogItemViewModel;
            if (deletedItem != null)
            {
                PublishDeletedItem(deletedItem);
            }
        }

        /// <summary>
        /// Publishes the deleted item.
        /// </summary>
        /// <param name="item">The item.</param>
        protected virtual void PublishDeletedItem(CatalogItemViewModel item)
        {
            Contract.Requires(EventAggregator != null);
            Contract.Requires(item != null);

            DocumentDeletedEvent documentDeletedEvent = EventAggregator.GetEvent<DocumentDeletedEvent>();
            documentDeletedEvent.Publish(item);
        }

        /// <summary>
        /// Gets a value indicating whether this instance can delete.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance can delete; otherwise, <c>false</c>.
        /// </value>
        protected virtual bool CanDelete
        {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Gets the save command.
        /// </summary>
        /// <value>The save command.</value>
        public virtual ICommand SaveCommand
        {
            get
            {
                Contract.Ensures(Contract.Result<ICommand>() != null);

                if (_saveCommand == null)
                {
                    _saveCommand = new RelayCommand(
                        param => Save(),
                        param => CanSave);
                }
                return _saveCommand;
            }
        }

        /// <summary>
        /// Saves the entity.
        /// </summary>
        public virtual void Save()
        {
            Contract.Requires(EventAggregator != null);

            CatalogItemViewModel savedItem = this as CatalogItemViewModel;
            if (savedItem != null)
            {
                DocumentSavedEvent documentSavedEvent = EventAggregator.GetEvent<DocumentSavedEvent>();
                documentSavedEvent.Publish(savedItem);
            }
        }

        /// <summary>
        /// Gets a value indicating whether the entity can be saved.
        /// </summary>
        /// <value><c>true</c> if the entity can be saved; otherwise, <c>false</c>.</value>
        protected virtual bool CanSave
        {
            get { throw new NotImplementedException(); }
        }
    }
}